<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>Hello world</title>
  <style>
  * {
    margin: 0;
    padding: 0;
  }

  .box {
    position: fixed;
    top: 50%;
    left: 50%;
    margin-top: -40vh;
    margin-left: -40vw;
    width: 80vw;
    height: 80vh;
  }

  .edit-wrapper {
    position: absolute;
    top: 0;
    left: 0;
    z-index: -10;
    opacity: 0;
    /*z-index: 10;
    opacity: 1;*/
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    overflow: hidden;
  }

  .edit-wrapper.is-show {
    z-index: 10;
    opacity: 1;
  }

  .edit-content {
    position: absolute;
    z-index: 10;
    opacity: 1;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    transform-origin: center;
  }

  .edit-content .close-btn {
    position: absolute;
    z-index: 50;
    top: 40px;
    right: 40px;
    text-align: center;
    width: 120px;
    height: 120px;
    line-height: 106px;
    border: 4px solid #fff;
    border-radius: 50%;
    font-size: 100px;
    cursor: pointer;
    color: #fff;
    box-sizing: content-box;
  }

  .aa {
    width: 100%;
    height: 100%;
    opacity: 1;
  }
  .btn-box {
    position: fixed;
    top: 40px;
    left: 40px;
    z-index: 10;
  }
  </style>
</head>

<body>
  <div class="btn-box">
    <button onclick="showEditLineClick()">显示线</button>
    <button onclick="showEditRectClick()">显示矩形</button>
    <button onclick="hideEdit()">隐藏</button>
  </div>
  <div class="box">
    <div class="aa"></div>
    <div class="edit-wrapper">
      <div class="edit-content">
        <div class="close-btn" onclick="oEdit.close()">×</div>
        <div style="width:100%; height:100%;" class="imageContainer"></div>
      </div>
    </div>
  </div>
  <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
  <script src="./static/hammer.js"></script>
  <script src="./static/cornerstone.min.js"></script>
  <script src="./static/cornerstoneMath.min.js"></script>
  <script src="./static/cornerstoneWADOImageLoader.min.js"></script>
  <script src="./static/cornerstoneWebImageLoader.min.js"></script>
  <script src="./static/cornerstoneTools.min.js"></script>
  <script src="./static/dicomParser.min.js"></script>
  <script>
  const baseUrl = "http://127.0.0.1:8000/static/js/";
  const image_uir = '111'

  var config = {
      "胸膜增厚": "rgb(255, 0, 255)",
      "纤维灶": "rgb(220, 20, 60)",
      "钙化": "rgb(148, 0, 211)",
      "骨折": "rgb(123, 104, 238)",
      "肺不张": "rgb(0, 0, 205)",
      "肿块": "rgb(30, 144, 255)",
      "结节": "rgb(184, 134, 11)",
      "肺气肿": "rgb(0, 139, 0)",
      "气胸": "rgb(139, 35, 35)",
      "PICC": "rgb(218, 165, 32)",
      "积液": "rgb(255, 140, 0)",
      "积气": "rgb(0, 0, 0)",
      "实变": "rgb(85, 107, 47)",
      "术后金属": "rgb(95, 158, 160)",
      "膈下游离气体": "rgb(9,113,175)",
      "肠道积气扩张": "rgb(4,248,194)",
      "肠道积液液平": "rgb(148, 0, 211)",
      "泌尿系统结石": "rgb(108,227,33)"
  }



  var infos = {
    '111_ctr': {
      center_x: 1277,
      heart_x_begin_left: 936,
      heart_x_end_right: 2100,
      heart_y_begin_left: 1531,
      heart_y_end_right: 1621,
      lung_x_begin: 170,
      lung_x_end: 2348,
      lung_y: 1565,
      ratio: 0.5344,
    },
    '111_current': [{"name": "纤维灶", "confidence": 0.681, "xmin": 941, "ymin": 1033, "xmax": 1355, "ymax": 1318}, {"name": "结节", "confidence": 0.272, "xmin": 1175, "ymin": 812, "xmax": 1241, "ymax": 877}, {"name": "实变", "confidence": 0.079, "xmin": 947, "ymin": 1030, "xmax": 1349, "ymax": 1294}, {"name": "结节", "confidence": 0.036, "xmin": 977, "ymin": 1032, "xmax": 1124, "ymax": 1182}]
  }

  window.onload = function() {
    _initCornerstone();

    aaInitCornerstone();
  }

  function _initCornerstone() {
    cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
    cornerstoneWADOImageLoader.external.dicomParser = dicomParser;
    cornerstoneTools.external.cornerstoneMath = cornerstoneMath;
    cornerstoneTools.external.cornerstone = cornerstone;
    cornerstoneTools.external.Hammer = Hammer;

    // Image Loader
    const config = {
      webWorkerPath: `${baseUrl}assets/image-loader/cornerstoneWADOImageLoaderWebWorker.js`,
      taskConfiguration: {
        decodeTask: {
          codecsPath: `${baseUrl}assets/image-loader/cornerstoneWADOImageLoaderCodecs.js`,
        },
      },
    };
    cornerstoneWADOImageLoader.webWorkerManager.initialize(config);
  }

  // 初始化影像
  function aaInitCornerstone() {
    let element = document.querySelector('.aa');
    cornerstone.enable(element);
    cornerstone.loadAndCacheImage('wadouri:http://localhost:8001/static/data/1.2.840.1.19439.0.1000.20220101101114.1153.10000.3383340/1.2.840.113564.12312312360.2022010110184045329.1003000225002').then(function(image) {

      var viewport = cornerstone.getDefaultViewportForImage(element, image);
      cornerstone.displayImage(element, image, viewport);
    });
    element.addEventListener('cornerstoneimagerendered', onImageRendered);
  }
  function onImageRendered(e) {
    oEdit.init(e);
  }

  // 显示编辑线
  function showEditLineClick() {
    oEdit.show('line', infos[image_uir+'_ctr']);
  }

  // 显示编辑线
  function showEditRectClick() {
    oEdit.show('rect', infos[image_uir+'_current']);
  }

  // 隐藏
  function hideEdit() {
    oEdit.close();
  }


  const oEdit = {
    visible: false,

    oWrapper: $('.edit-wrapper'),
    oContent: $('.edit-wrapper .edit-content'),
    oContainer: $('.edit-wrapper .imageContainer'),
    oCanvas: null,
    context: null,
    // 图片数据
    image: {
      ratio: 0,
      width: 0,
      height: 0,
      file: null
    },
    // 编辑类型，line线，rect方框
    editType: '',
    // 数据
    oldData: null,
    newData: null,
    startData: null,
    // 路径
    paths: [],
    oPath: null,
    // 显示
    show(type, data) {
      this.editType = type;
      this.oldData = JSON.parse(JSON.stringify(data));
      this.newData = JSON.parse(JSON.stringify(data));

      if(type == 'line') {
        this.drawLine();
      } else if(type == 'rect') {
        this.drawRect();
      }
      this.oWrapper.addClass('is-show');
      this.visible = true;
    },
    // 关闭
    close() {
      this.oWrapper.removeClass('is-show');
      this.visible = false;
    },
    // 初始化
    async init(e) {
      await this.initImageData(e);
      await waitTimeout(50);

      this.initEvent();
    },
    initEvent() {
      let context = this.context;
      var isDown = false;
      var downx = 0, downy = 0;

      this.oContainer.on('mousedown', 'canvas', (e) => {
        var canvas = this.oContainer[0].children[0];
        var rect = canvas.getBoundingClientRect();
        var x = e.clientX - rect.left;
        var y = e.clientY - rect.top;
        this.paths.forEach((item) => {
          if(context.isPointInPath(item.path, x/this.image.ratio, y/this.image.ratio)) {
            this.oPath = item;
            isDown = true;
            this.startCtr = JSON.parse(JSON.stringify(this.newData));
            downx = e.pageX;
            downy = e.pageY;
          }
        })
      })

      this.oContainer.on('mousemove', 'canvas', (e) => {
        // 如果当前是按下
        if(isDown) {
          var movex = e.pageX - downx;
          var movey = e.pageY - downy;
          if(this.editType == 'line') {
            this.saveLineData(this.oPath.key, this.oPath.dir, movex/this.image.ratio, movey/this.image.ratio);
          } else if (this.editType == 'rect') {
            this.saveRectData(this.oPath, movex/this.image.ratio, movey/this.image.ratio);
          }

        } else { // 非按下，移动改变canvas鼠标形状
          var canvas = this.oContainer[0].children[0];
          var rect = canvas.getBoundingClientRect();
          var x = e.clientX - rect.left;
          var y = e.clientY - rect.top;

          for(let i = 0; i < this.paths.length; i++) {
            let item = this.paths[i];
            if(context.isPointInPath(item.path, x/this.image.ratio, y/this.image.ratio)) {
              canvas.style.cursor = item.cursor;
              break;
            } else {
              canvas.style.cursor = '';
            }
          }
        }
      })

      window.addEventListener('mouseup', function () {
        isDown = false;
      })
    },

    // 初始化图片宽高
    async initImageData(e) {
      var image = e.detail.image;
      // 设置宽高
      this.oContent.width(image.width);
      this.oContent.height(image.height);
      // 设置比例
      var ratio = e.detail.viewport.scale;
      this.oContent.css({
        transform: `translate(-50%, -50%) scale(${ratio})`
      })
      this.image.ratio = ratio;

      // 设置图片
      cornerstone.enable(this.oContainer[0]);
      var viewport = cornerstone.getDefaultViewportForImage(this.oContainer[0], image);
      cornerstone.displayImage(this.oContainer[0], image, viewport);
      await waitTimeout(50);

      // 获取ctx对象
      this.oCanvas = this.oContainer[0].children[0];
      this.context = this.oCanvas.getContext('2d');
      // 保存图片
      var base64 = this.oCanvas.toDataURL('image/png');
      var img = new Image();
      img.src = base64;
      this.image.file = img;
    },

    // 保存线数据
    saveLineData(key, dir, movex, movey) {
      this.newData[key] = (dir == 'x' ? movex : movey)+this.startCtr[key];

      // 清空画布
      this.oCanvas.width = this.oCanvas.width;
      // 绘制底图
      this.drawImage();
      // 画线
      this.drawLine();
    },

    // 保存矩形数据
    saveRectData(path, movex, movey) {
      let index = path.index;
      if(path.dir == 'xy') {
        this.newData[index].xmin = movex+this.startCtr[index].xmin;
        this.newData[index].xmax = movex+this.startCtr[index].xmax;
        this.newData[index].ymin = movey+this.startCtr[index].ymin;
        this.newData[index].ymax = movey+this.startCtr[index].ymax;
      } else {
        this.newData[index][path.key] = (path.dir == 'x' ? movex : movey)+this.startCtr[index][path.key];
      }
      // 清空画布
      this.oCanvas.width = this.oCanvas.width;
      // 绘制底图
      this.drawImage();
      // 画矩形
      this.drawRect();
    },

    // 绘制底图
    drawImage() {
      this.context.drawImage(this.image.file,0,0);
    },

    // 画线
    drawLine() {
      let ctr = this.newData;
      let context = this.context;
      let paths = [];

      let path = null;

      context.beginPath();
      context.lineWidth = 15;
      context.strokeStyle = "green"
      context.moveTo(ctr.lung_x_begin, ctr.lung_y);
      context.lineTo(ctr.lung_x_end, ctr.lung_y);
      context.closePath();
      context.stroke();

      // 绿色中线
      path = new Path2D();
      path.moveTo(ctr.lung_x_begin+20, ctr.lung_y-8);
      path.lineTo(ctr.lung_x_end-20, ctr.lung_y-8);
      path.lineTo(ctr.lung_x_end-20, ctr.lung_y+8);
      path.lineTo(ctr.lung_x_begin+20, ctr.lung_y+8);
      paths.push({
        cursor: 'n-resize',
        dir: 'y',
        path: path,
        key: 'lung_y'
      });
      // 绿色左
      path = new Path2D();
      path.moveTo(ctr.lung_x_begin, ctr.lung_y-8);
      path.lineTo(ctr.lung_x_begin+20, ctr.lung_y-8);
      path.lineTo(ctr.lung_x_begin+20, ctr.lung_y+8);
      path.lineTo(ctr.lung_x_begin, ctr.lung_y+8);
      paths.push({
        cursor: 'e-resize',
        dir: 'x',
        path: path,
        key: 'lung_x_begin'
      });
      // 绿色右
      path = new Path2D();
      path.moveTo(ctr.lung_x_end-20, ctr.lung_y-8);
      path.lineTo(ctr.lung_x_end, ctr.lung_y-8);
      path.lineTo(ctr.lung_x_end, ctr.lung_y+8);
      path.lineTo(ctr.lung_x_end-20, ctr.lung_y+8);
      paths.push({
        cursor: 'e-resize',
        dir: 'x',
        path: path,
        key: 'lung_x_end'
      });


      centerX = (ctr.lung_x_begin + ctr.lung_x_end) / 2
      Y = [ctr.lung_y, ctr.heart_y_begin_left, ctr.heart_y_end_right]
      minY = Math.min(...Y)
      maxY = Math.max(...Y)
      context.strokeStyle = "black"
      context.beginPath();
      context.moveTo(centerX, minY - 50);
      context.lineTo(centerX, maxY + 50);
      context.closePath();
      context.stroke();


      context.strokeStyle = "red"
      context.beginPath();
      context.moveTo(ctr.heart_x_begin_left, ctr.heart_y_begin_left);
      context.lineTo(centerX, ctr.heart_y_begin_left);
      context.closePath();
      context.stroke();

      // 红色线
      path = new Path2D();
      path.moveTo(ctr.heart_x_begin_left+20, ctr.heart_y_begin_left-8);
      path.lineTo(centerX, ctr.heart_y_begin_left-8);
      path.lineTo(centerX, ctr.heart_y_begin_left+8);
      path.lineTo(ctr.heart_x_begin_left+20, ctr.heart_y_begin_left+8);
      paths.push({
        cursor: 'n-resize',
        dir: 'y',
        path: path,
        key: 'heart_y_begin_left'
      });
      // 红色左
      path = new Path2D();
      path.moveTo(ctr.heart_x_begin_left, ctr.heart_y_begin_left-8);
      path.lineTo(ctr.heart_x_begin_left+20, ctr.heart_y_begin_left-8);
      path.lineTo(ctr.heart_x_begin_left+20, ctr.heart_y_begin_left+8);
      path.lineTo(ctr.heart_x_begin_left, ctr.heart_y_begin_left+8);
      paths.push({
        cursor: 'e-resize',
        dir: 'x',
        path: path,
        key: 'heart_x_begin_left'
      });

      context.beginPath();
      context.moveTo(centerX, ctr.heart_y_end_right);
      context.lineTo(ctr.heart_x_end_right, ctr.heart_y_end_right);
      context.closePath();
      context.stroke();
  
      // 红色线
      path = new Path2D();
      path.moveTo(centerX, ctr.heart_y_end_right-8);
      path.lineTo(ctr.heart_x_end_right-20, ctr.heart_y_end_right-8);
      path.lineTo(ctr.heart_x_end_right-20, ctr.heart_y_end_right+8);
      path.lineTo(centerX, ctr.heart_y_end_right+8);
      paths.push({
        cursor: 'n-resize',
        dir: 'y',
        path: path,
        key: 'heart_y_end_right'
      });
      // 红色右
      path = new Path2D();
      path.moveTo(ctr.heart_x_end_right-20, ctr.heart_y_end_right-8);
      path.lineTo(ctr.heart_x_end_right, ctr.heart_y_end_right-8);
      path.lineTo(ctr.heart_x_end_right, ctr.heart_y_end_right+8);
      path.lineTo(ctr.heart_x_end_right-20, ctr.heart_y_end_right+8);
      paths.push({
        cursor: 'e-resize',
        dir: 'x',
        path: path,
        key: 'heart_x_end_right'
      });

      this.paths = paths.reverse();
    },

    // 画矩形
    drawRect() {
      let list = this.newData;
      let context = this.context;
      let paths = [];

      let path = null;

      for(let i = 0; i < list.length; i++) {
        let item = list[i];
        let confidence = item.confidence;
        let label = item.name;
        let color = config[label];

        if (confidence !== 1) {
          label = label + " " + confidence;
        }

        let xmin = item.xmin;
        let ymin = item.ymin;
        let xmax = item.xmax;
        let ymax = item.ymax;

        context.fillStyle = color;
        context.strokeStyle = color;
        context.lineWidth = 8;
        context.font = "60px 微软雅黑"
        context.beginPath();
        context.moveTo(xmin, ymin);
        context.lineTo(xmin, ymax);
        context.lineTo(xmax, ymax);
        context.lineTo(xmax, ymin);
        context.lineTo(xmin, ymin);
        context.fillText(label, xmin, ymin - 1)
        context.fillRect(xmin, ymin - 60, context.measureText(label).width, 60);
        context.closePath();
        context.stroke();
        context.fillStyle = "white"
        context.fillText(label, xmin, ymin - 1);

        // 添加path
        // 上
        path = new Path2D();
        path.moveTo(xmin+4, ymin-4);
        path.lineTo(xmax-4, ymin-4);
        path.lineTo(xmax-4, ymin+4);
        path.lineTo(xmin+4, ymin+4);
        paths.push({
          cursor: 'n-resize',
          dir: 'y',
          path: path,
          key: 'ymin',
          index: i
        });
        // 右
        path = new Path2D();
        path.moveTo(xmax-4, ymin+4);
        path.lineTo(xmax-4, ymax-4);
        path.lineTo(xmax+4, ymax+4);
        path.lineTo(xmax+4, ymin-4);
        paths.push({
          cursor: 'e-resize',
          dir: 'x',
          path: path,
          key: 'xmax',
          index: i
        });
        // 下
        path = new Path2D();
        path.moveTo(xmin+4, ymax-4);
        path.lineTo(xmax-4, ymax-4);
        path.lineTo(xmax-4, ymax+4);
        path.lineTo(xmin+4, ymax+4);
        paths.push({
          cursor: 's-resize',
          dir: 'y',
          path: path,
          key: 'ymax',
          index: i
        });
        // 左
        path = new Path2D();
        path.moveTo(xmin-4, ymin+4);
        path.lineTo(xmin-4, ymax-4);
        path.lineTo(xmin+4, ymax-4);
        path.lineTo(xmin+4, ymin+4);
        paths.push({
          cursor: 'w-resize',
          dir: 'x',
          path: path,
          key: 'xmin',
          index: i
        });
        // 中心
        path = new Path2D();
        path.moveTo(xmin+4, ymin+4);
        path.lineTo(xmin+4, ymax-4);
        path.lineTo(xmax-4, ymax-4);
        path.lineTo(xmax-4, ymin+4);
        path.lineTo(xmin+4, ymin+4);
        paths.push({
          cursor: 'move',
          dir: 'xy',
          path: path,
          index: i
        });
      }
      this.paths = paths.reverse();
    }
  }


  const waitTimeout = function (time) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve();
      }, time);
    })
  }
  </script>
</body>

</html>